bitkeeper revision 1.1159.199.1 (41ab4412dnDymGEqZNhEzt67Yzgmxw)
authorkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 29 Nov 2004 15:45:22 +0000 (15:45 +0000)
committerkaf24@scramble.cl.cam.ac.uk <kaf24@scramble.cl.cam.ac.uk>
Mon, 29 Nov 2004 15:45:22 +0000 (15:45 +0000)
MTRR support for privileged kernels. Should help our X-server support.

.rootkeys
linux-2.6.9-xen-sparse/arch/xen/configs/xen0_defconfig
linux-2.6.9-xen-sparse/arch/xen/i386/Kconfig
linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/Makefile
linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/Makefile [new file with mode: 0644]
linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/main.c [new file with mode: 0644]
linux-2.6.9-xen-sparse/include/asm-xen/asm-i386/mach-xen/setup_arch_post.h
xen/arch/x86/dom0_ops.c
xen/include/public/dom0_ops.h

index e92266e5c15c1eba907cf61d3f8b89d391088eef..8bda240f8f4ba009628a6a35d933f45e6c53d935 100644 (file)
--- a/.rootkeys
+++ b/.rootkeys
 40f56238eczveJ86k_4hNxCLRQIF-g linux-2.6.9-xen-sparse/arch/xen/i386/kernel/Makefile
 40f56238rXVTJQKbBuXXLH52qEArcg linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/Makefile
 40f562385s4lr6Zg92gExe7UQ4A76Q linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/common.c
+41ab440bnpxZdWShZrGgM9pPaz5rmA linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/Makefile
+41ab440bBKWz-aEOEojU4PAMXe3Ppg linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/main.c
 40f56238XDtHSijkAFlbv1PT8Bhw_Q linux-2.6.9-xen-sparse/arch/xen/i386/kernel/entry.S
 40f56238bnvciAuyzAiMkdzGErYt1A linux-2.6.9-xen-sparse/arch/xen/i386/kernel/head.S
 40f58a0d31M2EkuPbG94ns_nOi0PVA linux-2.6.9-xen-sparse/arch/xen/i386/kernel/i386_ksyms.c
index 80bd0dbc2a7bfa008aea8baa6020240991f42a5f..7d7cd9b99b4847f6e932739f50989cf99d9e422c 100644 (file)
@@ -110,6 +110,7 @@ CONFIG_X86_CPUID=y
 # CONFIG_EDD is not set
 CONFIG_NOHIGHMEM=y
 # CONFIG_HIGHMEM4G is not set
+CONFIG_MTRR=y
 CONFIG_HAVE_DEC_LOCK=y
 # CONFIG_REGPARM is not set
 
index 6e22f7ca215c4ead46a5e066846ce95fd400c201..02b89bcb9f1794e549ea006ff4d1fdf288c281eb 100644 (file)
@@ -564,6 +564,11 @@ config HAVE_ARCH_BOOTMEM_NODE
 #        low memory.  Setting this option will put user-space page table
 #        entries in high memory.
 
+config MTRR
+       bool
+       depends on XEN_PRIVILEGED_GUEST
+       default y
+
 #config MTRR
 #       bool "MTRR (Memory Type Range Register) support"
 #       ---help---
index 478e023a6d6219cb240ae053b3a1bbcf4df94863..2f65f0a835b245fc0800fb1c0ae1832fc9b6f0a9 100644 (file)
@@ -18,7 +18,7 @@ c-obj-y       +=      umc.o
 
 #obj-$(CONFIG_X86_MCE) +=      ../../../../i386/kernel/cpu/mcheck/
 
-#obj-$(CONFIG_MTRR)    +=      ../../../../i386/kernel/cpu/mtrr/
+obj-$(CONFIG_MTRR)     +=      mtrr/
 #obj-$(CONFIG_CPU_FREQ)        +=      ../../../../i386/kernel/cpu/cpufreq/
 
 c-link :=
diff --git a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/Makefile b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/Makefile
new file mode 100644 (file)
index 0000000..e25eb72
--- /dev/null
@@ -0,0 +1,16 @@
+obj-y  := main.o
+c-obj-y        := if.o
+
+c-link :=
+
+$(patsubst %.o,$(obj)/%.c,$(c-obj-y) $(c-link)): $(obj)/mtrr.h
+       @ln -fsn $(srctree)/arch/i386/kernel/cpu/mtrr/$(notdir $@) $@
+
+$(patsubst %.o,$(obj)/%.c,$(obj-y)): $(obj)/mtrr.h
+
+$(obj)/mtrr.h:
+       @ln -fsn $(srctree)/arch/i386/kernel/cpu/mtrr/mtrr.h $@
+
+obj-y  += $(c-obj-y)
+
+clean-files += $(patsubst %.o,%.c,$(c-obj-y) $(c-obj-) $(c-link))
diff --git a/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/main.c b/linux-2.6.9-xen-sparse/arch/xen/i386/kernel/cpu/mtrr/main.c
new file mode 100644 (file)
index 0000000..c06cf93
--- /dev/null
@@ -0,0 +1,165 @@
+#include <linux/init.h>
+#include <linux/proc_fs.h>
+#include <linux/ctype.h>
+#include <linux/module.h>
+#include <linux/seq_file.h>
+#include <asm/uaccess.h>
+
+#include <asm/mtrr.h>
+#include "mtrr.h"
+
+void generic_get_mtrr(unsigned int reg, unsigned long *base,
+                     unsigned int *size, mtrr_type * type)
+{
+       dom0_op_t op;
+
+       op.cmd = DOM0_READ_MEMTYPE;
+       op.u.read_memtype.reg = reg;
+       (void)HYPERVISOR_dom0_op(&op);
+
+       *size = op.u.read_memtype.nr_pfns;
+       *base = op.u.read_memtype.pfn;
+       *type = op.u.read_memtype.type;
+}
+
+struct mtrr_ops generic_mtrr_ops = {
+       .use_intel_if      = 1,
+       .get               = generic_get_mtrr,
+};
+
+struct mtrr_ops *mtrr_if = &generic_mtrr_ops;
+unsigned int num_var_ranges;
+unsigned int *usage_table;
+
+void __init set_num_var_ranges(void)
+{
+       dom0_op_t op;
+
+       for (num_var_ranges = 0; ; num_var_ranges++) {
+               op.cmd = DOM0_READ_MEMTYPE;
+               op.u.read_memtype.reg = num_var_ranges;
+               if (HYPERVISOR_dom0_op(&op) != 0)
+                       break;
+       }
+}
+
+static void __init init_table(void)
+{
+       int i, max;
+
+       max = num_var_ranges;
+       if ((usage_table = kmalloc(max * sizeof *usage_table, GFP_KERNEL))
+           == NULL) {
+               printk(KERN_ERR "mtrr: could not allocate\n");
+               return;
+       }
+       for (i = 0; i < max; i++)
+               usage_table[i] = 0;
+}
+
+int mtrr_add_page(unsigned long base, unsigned long size, 
+                 unsigned int type, char increment)
+{
+       int error;
+       dom0_op_t op;
+
+       op.cmd = DOM0_ADD_MEMTYPE;
+       op.u.add_memtype.pfn     = base;
+       op.u.add_memtype.nr_pfns = size;
+       op.u.add_memtype.type    = type;
+       if ((error = HYPERVISOR_dom0_op(&op)))
+               return error;
+
+       if (increment)
+               ++usage_table[op.u.add_memtype.reg];
+
+       return op.u.add_memtype.reg;
+}
+
+int
+mtrr_add(unsigned long base, unsigned long size, unsigned int type,
+        char increment)
+{
+       if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+               printk(KERN_WARNING "mtrr: size and base must be multiples of 4 kiB\n");
+               printk(KERN_DEBUG "mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
+               return -EINVAL;
+       }
+       return mtrr_add_page(base >> PAGE_SHIFT, size >> PAGE_SHIFT, type,
+                            increment);
+}
+
+int mtrr_del_page(int reg, unsigned long base, unsigned long size)
+{
+       int i, max;
+       mtrr_type ltype;
+       unsigned long lbase;
+       unsigned int lsize;
+       int error = -EINVAL;
+       dom0_op_t op;
+
+       max = num_var_ranges;
+       if (reg < 0) {
+               /*  Search for existing MTRR  */
+               for (i = 0; i < max; ++i) {
+                       mtrr_if->get(i, &lbase, &lsize, &ltype);
+                       if (lbase == base && lsize == size) {
+                               reg = i;
+                               break;
+                       }
+               }
+               if (reg < 0) {
+                       printk(KERN_DEBUG "mtrr: no MTRR for %lx000,%lx000 found\n", base,
+                              size);
+                       goto out;
+               }
+       }
+       if (usage_table[reg] < 1) {
+               printk(KERN_WARNING "mtrr: reg: %d has count=0\n", reg);
+               goto out;
+       }
+       if (--usage_table[reg] < 1) {
+               op.cmd = DOM0_DEL_MEMTYPE;
+               op.u.del_memtype.handle = 0;
+               op.u.add_memtype.reg    = reg;
+               (void)HYPERVISOR_dom0_op(&op);
+       }
+       error = reg;
+ out:
+       return error;
+}
+
+int
+mtrr_del(int reg, unsigned long base, unsigned long size)
+{
+       if ((base & (PAGE_SIZE - 1)) || (size & (PAGE_SIZE - 1))) {
+               printk(KERN_INFO "mtrr: size and base must be multiples of 4 kiB\n");
+               printk(KERN_DEBUG "mtrr: size: 0x%lx  base: 0x%lx\n", size, base);
+               return -EINVAL;
+       }
+       return mtrr_del_page(reg, base >> PAGE_SHIFT, size >> PAGE_SHIFT);
+}
+
+EXPORT_SYMBOL(mtrr_add);
+EXPORT_SYMBOL(mtrr_del);
+
+static int __init mtrr_init(void)
+{
+       struct cpuinfo_x86 *c = &boot_cpu_data;
+
+       if (!(xen_start_info.flags & SIF_PRIVILEGED))
+               return -ENODEV;
+
+       if ((!cpu_has(c, X86_FEATURE_MTRR)) &&
+           (!cpu_has(c, X86_FEATURE_K6_MTRR)) &&
+           (!cpu_has(c, X86_FEATURE_CYRIX_ARR)) &&
+           (!cpu_has(c, X86_FEATURE_CENTAUR_MCR)))
+               return -ENODEV;
+
+       set_num_var_ranges();
+       init_table();
+
+       return 0;
+}
+
+subsys_initcall(mtrr_init);
index 8f6c7b2daa64af11aaad097f3a52f23548624dd7..3791c91ae0da841998cbe1d25a2ee81dd35b3a83 100644 (file)
@@ -28,8 +28,9 @@ void __init machine_specific_modify_cpu_capabilities(struct cpuinfo_x86 *c)
        clear_bit(X86_FEATURE_DE, c->x86_capability);
        clear_bit(X86_FEATURE_PSE, c->x86_capability);
        clear_bit(X86_FEATURE_PGE, c->x86_capability);
-       clear_bit(X86_FEATURE_MTRR, c->x86_capability);
        clear_bit(X86_FEATURE_FXSR, c->x86_capability);
+       if (!(xen_start_info.flags & SIF_PRIVILEGED))
+               clear_bit(X86_FEATURE_MTRR, c->x86_capability);
 }
 
 extern void hypervisor_callback(void);
index 057a8b3e77537e805271953ba1357ee5d9c8dbde..b632e539c7281ea5145b3733f0cd5924cee9b116 100644 (file)
@@ -21,6 +21,9 @@
 #include <asm/shadow.h>
 #include <public/sched_ctl.h>
 
+#include <asm/mtrr.h>
+#include "mtrr/mtrr.h"
+
 #define TRC_DOM0OP_ENTER_BASE  0x00020000
 #define TRC_DOM0OP_LEAVE_BASE  0x00030000
 
@@ -93,6 +96,40 @@ long arch_do_dom0_op(dom0_op_t *op, dom0_op_t *u_dom0_op)
     }
     break;
 
+    case DOM0_ADD_MEMTYPE:
+    {
+        ret = mtrr_add_page(
+            op->u.add_memtype.pfn,
+            op->u.add_memtype.nr_pfns,
+            op->u.add_memtype.type,
+            1);
+    }
+    break;
+
+    case DOM0_DEL_MEMTYPE:
+    {
+        ret = mtrr_del_page(op->u.del_memtype.reg, 0, 0);
+    }
+    break;
+
+    case DOM0_READ_MEMTYPE:
+    {
+        unsigned long pfn;
+        unsigned int  nr_pfns;
+        mtrr_type     type;
+
+        ret = -EINVAL;
+        if ( op->u.read_memtype.reg < num_var_ranges )
+        {
+            mtrr_if->get(op->u.read_memtype.reg, &pfn, &nr_pfns, &type);
+            (void)__put_user(pfn, &u_dom0_op->u.read_memtype.pfn);
+            (void)__put_user(nr_pfns, &u_dom0_op->u.read_memtype.nr_pfns);
+            (void)__put_user(type, &u_dom0_op->u.read_memtype.type);
+            ret = 0;
+        }
+    }
+    break;
+
     default:
         ret = -ENOSYS;
 
index 9339bcc318571af14432e0fb39f4801edb0954fb..f8c7bab6d31206aa3ac82bff1bb949fd3c807903 100644 (file)
@@ -336,6 +336,56 @@ typedef struct {
     u32          type;                /*  8: vm_assist cmd */
 } PACKED dom0_setdomainvmassist_t; /* 12 bytes */
 
+/*
+ * Request memory range (@pfn, @pfn+@nr_pfns-1) to have type @type.
+ * On x86, @type is an architecture-defined MTRR memory type.
+ * On success, returns the MTRR that was used (@reg) and a handle that can
+ * be passed to DOM0_DEL_MEMTYPE to accurately tear down the new setting.
+ * (x86-specific).
+ */
+#define DOM0_ADD_MEMTYPE         31
+typedef struct {
+    /* IN variables. */
+    memory_t pfn;                     /*  0 */
+    MEMORY_PADDING;
+    memory_t nr_pfns;                 /*  8 */
+    MEMORY_PADDING;
+    u32      type;                    /* 16 */
+    u32      __pad0;
+    /* OUT variables. */
+    u32      handle;                  /* 24 */
+    u32      reg;                     /* 28 */
+} PACKED dom0_add_memtype_t; /* 32 bytes */
+
+/*
+ * Tear down an existing memory-range type. If @handle is remembered then it
+ * should be passed in to accurately tear down the correct setting (in case
+ * of overlapping memory regions with differing types). If it is not known
+ * then @handle should be set to zero. In all cases @reg must be set.
+ * (x86-specific).
+ */
+#define DOM0_DEL_MEMTYPE         32
+typedef struct {
+    /* IN variables. */
+    u32      handle;                  /*  0 */
+    u32      reg;                     /*  4 */
+} PACKED dom0_del_memtype_t; /* 8 bytes */
+
+/* Read current type of an MTRR (x86-specific). */
+#define DOM0_READ_MEMTYPE        33
+typedef struct {
+    /* IN variables. */
+    u32      reg;                     /*  0 */
+    u32      __pad0;
+    /* OUT variables. */
+    memory_t pfn;                     /*  8 */
+    MEMORY_PADDING;
+    memory_t nr_pfns;                 /* 16 */
+    MEMORY_PADDING;
+    u32      type;                    /* 24 */
+    u32      __pad1;
+} PACKED dom0_read_memtype_t; /* 32 bytes */
+
 typedef struct {
     u32 cmd;                          /* 0 */
     u32 interface_version;            /* 4 */ /* DOM0_INTERFACE_VERSION */
@@ -366,6 +416,9 @@ typedef struct {
        dom0_setdomainmaxmem_t   setdomainmaxmem;
        dom0_getpageframeinfo2_t getpageframeinfo2;
        dom0_setdomainvmassist_t setdomainvmassist;
+        dom0_add_memtype_t       add_memtype;
+        dom0_del_memtype_t       del_memtype;
+        dom0_read_memtype_t      read_memtype;
     } PACKED u;
 } PACKED dom0_op_t; /* 80 bytes */